<script setup lang="ts">
import {computed, onMounted, ref, toRaw, watch} from "vue";
import {type FormInst, useMessage} from "naive-ui";
import CustomModal from "@components/CustomModal/index.ts";
import {getRequest, postOrputRequest} from "@/api";
import {flattenTreeWithParent, isSubset} from "@/utils";

interface RoleItem {
  id: number
  name: string | null
  desc: string | null
  permissions: (number | string)[]
}

const message = useMessage()

const menusData = ref<PermissionItem[]>([])

const visible = defineModel('visible', {type: Boolean, default: false});
const props = defineProps<{
  formData?: Recordable;
}>();

const emits = defineEmits(["closeModal"])

const handelSubmitLoading = ref<boolean>(false)
const formRef = ref<FormInst | null>(null)

const flattenRolePermission = ref<FlattenPermissionItem[]>([]);

const allChecked=ref<boolean>(false);

const addEditForm = ref<RoleItem>({
  id: 0,
  name: null,
  desc: null,
  permissions: [],
})

// 默认表单值，用于重置
const defaultFormValues: RoleItem = {
  id: 0,
  name: null,
  desc: null,
  permissions: [],
}
const addEditFormRules = ref({
  name: {
    required: true,
    message: '请输入角色名称',
    trigger: ['input', 'blur'],
  },
  desc: {
    required: true,
    message: '请输入角色描述',
    trigger: ['input', 'blur'],
  },
  permissions: {
    type: 'array',
    required: true,
    message: '请选择权限',
    trigger: 'change',
  }
})

// 计算选中数量
const selectedPermissionCount = computed(() => addEditForm.value.permissions?.length || 0);

// 计算总权限数量
const totalPermissionCount = computed(() => flattenRolePermission.value.length);

// 计算是否全选
const isActuallyAllChecked = computed(() =>
    selectedPermissionCount.value > 0 &&
    selectedPermissionCount.value === totalPermissionCount.value
);

// 计算是否为不确定状态
const indeterminateCheckAll = computed(() =>
    selectedPermissionCount.value > 0 &&
    selectedPermissionCount.value < totalPermissionCount.value
);

//确认提交数据
const confirmBtn = () => {
  formRef.value?.validate((errors) => {
    if (!errors) {
      handelSubmitLoading.value = true;
      postOrputRequest('/role/save', addEditForm.value).then((res: ResponseResult) => {
        if (res.code === 200) {
          message.success(res.message, {
            duration: 1500,
            onLeave() {
              visible.value = false
              emits('closeModal', addEditForm.value.id ? 2 : 1)
            }
          })
        } else {
          message.error(res.message);
          handelSubmitLoading.value = false;
        }
      })
    }
  })
}

// 关闭模态框
const closeModal = () => {
  // 使用Object.assign快速重置表单
  Object.assign(addEditForm.value, defaultFormValues)
  handelSubmitLoading.value = false
}

// 全选/反选
const checkedAll = (checked: boolean) => {
  if (checked) {
    // 全选所有权限的 key
    addEditForm.value.permissions = flattenRolePermission.value.map(item => item.key);
  } else {
    // 清空选择
    addEditForm.value.permissions = [];
  }
}

//选择权限
const checkPermission = (_value: (string | number)[], meta: {
  actionType: 'check' | 'uncheck',
  value: string | number
}) => {
  const parentIds = findMenuParent(menusData.value, meta.value);
  let newPermissionList: (number | string)[] = [...(addEditForm.value.permissions || [])];

  // 处理父级数据
  const processParent = (currentList: (string | number)[]) => {
    if (!parentIds?.length) return currentList;

    const childIds: (string | number)[] = findChildrenKeysSimplified(menusData.value, parentIds[0]);
    if (!isSubset(currentList, childIds)) {
      // 如果子级没有全选，移除父级
      return currentList.filter(x => x !== parentIds[0]);
    }
    return currentList;
  };

  if (meta.actionType === 'check') {
    if (parentIds?.length) {
      newPermissionList = reductionPermission(parentIds);
    } else {
      newPermissionList = reductionPermission(findChildrenKeysSimplified(menusData.value, meta.value))
    }

  } else {
    // 取消选中
    const obj = toRaw(flattenRolePermission.value.find((item: PermissionItem) => item.key === meta.value));

    if (obj?.types === 1 || obj?.types === 2) {
      const childIds: (string | number)[] = findChildrenKeysSimplified(menusData.value, obj.key);

      // 先移除子级权限
      if (childIds?.length) {
        newPermissionList = newPermissionList.filter(x => !childIds.includes(x));
      }
      // 再处理父级权限
      newPermissionList = processParent(newPermissionList);
    }
    // 其他类型权限不需要特殊处理
  }
  addEditForm.value.permissions = newPermissionList;
}

// 递归查找父节点
function findMenuParent(treeData: PermissionItem[], key: string | number | boolean): (string | number)[] {
  for (const item of treeData) {
    if (item.key === key) return [];
    if (item.children) {
      const res = findMenuParent(item.children, key);
      if (res.length !== 0 || (item.children.some((c: PermissionItem) => c.key === key))) {
        return [...res, item.key];
      }
    }
  }
  return [];
}

function findChildrenKeysSimplified(menuData: PermissionItem[], targetKey: number | string): number[] {
  const result: number[] = [];

  function findTarget(items: PermissionItem[]): PermissionItem | null {
    for (const item of items) {
      if (item.key === targetKey) return item;
      if (item.children) {
        const found = findTarget(item.children);
        if (found) return found;
      }
    }
    return null;
  }

  function collectKeys(item: PermissionItem): void {
    if (item.children) {
      item.children.forEach(child => {
        result.push(child.key);
        collectKeys(child);
      });
    }
  }

  const targetItem = findTarget(menuData);
  if (targetItem && targetItem.children) {
    targetItem.children.forEach(child => {
      result.push(child.key);
      collectKeys(child);
    });
  }

  return result;
}

// 权限去重
function reductionPermission(data: (number | string)[]): (number | string)[] {
  const newPermissionList = new Map();
  return [...addEditForm.value.permissions, ...data].filter((item) => !newPermissionList.has(item) && newPermissionList.set(item, true));
}

const getMenusData = async () => {
  const res = await getRequest<PermissionItem[]>("/menus/get_permission");
  const list = res.data ?? [];
  menusData.value = list;
  flattenRolePermission.value = flattenTreeWithParent(list);
};


watch(() => props.formData, (newValue) => {
  if (newValue && Object.keys(newValue).length > 0) {
    Object.assign(addEditForm.value, {
      ...defaultFormValues,
      ...newValue
    })
  }
}, {immediate: true, deep: true})

watch(isActuallyAllChecked, (newValue) => {
  allChecked.value = newValue
}, { immediate: true })

onMounted(() => {
  getMenusData()
})
</script>

<template>
  <custom-modal v-model:show="visible"
                :widths="580"
                :handel-submit-loading="handelSubmitLoading"
                @confirm="confirmBtn"
                @after-leave="closeModal"
                confirmText="确认"
                :title="`${addEditForm.id?'编辑':'新增'}角色`">
    <template #default>
      <n-form ref="formRef"
              :model="addEditForm"
              :rules="addEditFormRules"
              require-mark-placement="left"
              label-placement="left">
        <n-form-item label="名称" path="name">
          <n-input v-model:value="addEditForm.name" placeholder="请输入角色名称" clearable/>
        </n-form-item>
        <n-form-item label="描述" path="desc">
          <n-input v-model:value="addEditForm.desc"
                   type="textarea"
                   :autosize="{minRows: 2}"
                   placeholder="请输入角色描述"/>
        </n-form-item>
        <n-form-item label="权限" path="permissions">
          <div style="position: relative;top: 4px;">
            <div class="all-checked">
              <n-checkbox v-model:checked="allChecked" :indeterminate="indeterminateCheckAll"
                          @update:checked="checkedAll">
                {{ allChecked ? '全取消' : !allChecked && indeterminateCheckAll ? '已部分选中/全选' : '全选' }}
              </n-checkbox>
            </div>
            <div class="permission-list">
              <n-checkbox-group v-model:value="addEditForm.permissions" @update:value="checkPermission">
                <template v-for="item in menusData" :key="item.key">
                  <div class="permission-list-directory">
                    <n-checkbox :value="item.key">{{ item.label }}{{ item.children ? ':' : '' }}</n-checkbox>
                    <template v-for="menu in item.children" :key="menu.key">
                      <div class="permission-list-menu">
                        <n-checkbox :value="menu.key">{{ menu.label }}{{ menu.children ? ':' : '' }}</n-checkbox>
                        <div class="permission-list-menu-act" v-if="menu.children">
                          <n-space>
                            <template v-for="act in menu.children" :key="act.key">
                              <n-checkbox :value="act.key">{{ act.label }}</n-checkbox>
                            </template>
                          </n-space>
                        </div>
                      </div>
                    </template>
                  </div>
                </template>
              </n-checkbox-group>
            </div>
          </div>
        </n-form-item>
      </n-form>
    </template>
  </custom-modal>
</template>

<style scoped lang="scss">
.permission-list {
  max-height: 360px;
  overflow: auto;

  &-menu, &-menu-act {
    padding-left: 25px;
  }
}
</style>